<template>
    <div class="home">
        <el-container style="height: 100vh">
            <el-header class="header">恶意桌面应用检测系统</el-header>
            <el-main>
                <div style="width: 90%; margin: 20px auto">
                    <el-tabs style="background-color: #fff" v-model="activeName" class="tabs" type="border-card"
                        @tab-click="handleClick">
                        <el-tab-pane label="特征分析" name="1">
                            <div class="btn_group">
                                <el-switch v-model="pe_switch" active-text="PE" inactive-text="ELF"
                                    style="--el-switch-off-color: #13ce66;margin:0 10px" />
                                <el-upload class="margin_right" action="" multiple :http-request="upload"
                                    :before-upload="pe_switch ? format_check_pe : format_check_elf"
                                    :show-file-list="false" accept="application/x-msdownload">
                                    <el-button v-if="pe_switch" type="primary">上传PE文件</el-button>
                                    <el-button v-else type="primary">上传ELF文件</el-button></el-upload>
                            </div>
                            <el-divider></el-divider>
                            <div class="list_box">
                                <div v-for="item in pe_list" :key="item.id">
                                    <Mycard :info="item" :show_download="true" :show_view="true"
                                        @download="download_features('pe', item.filename, item.id)"
                                        @view="view_features('pe', item.filename, item.id, item.filetype)">
                                    </Mycard>
                                </div>
                                <el-empty v-if="pe_list.length == 0" description="点击按钮上传文件" />
                            </div>
                        </el-tab-pane>
                        <el-tab-pane label="特征检测" name="2">
                            <div class="btn_group">
                                <el-upload class="margin_right" action="" multiple :http-request="upload_vec"
                                    :before-upload="format_check_json" :show-file-list="false"
                                    accept="application/json">
                                    <el-button type="primary">上传特征文件</el-button></el-upload>
                            </div>
                            <el-divider></el-divider>
                            <div class="list_box">
                                <div v-for="item in result_list" :key="item.id">
                                    <Mycard :info="item">
                                    </Mycard>
                                </div>
                                <el-empty v-if="result_list.length == 0" description="点击按钮上传文件" />
                            </div>
                        </el-tab-pane>
                    </el-tabs>
                </div>
            </el-main>
        </el-container>
        <el-dialog v-model="dialog_pe" title="特征预览">
            <el-form :model="features_pe" label-width="auto">
                <el-form-item label="api"><el-input v-model="features_pe.api" type="textarea" /></el-form-item>
                <el-form-item label="dll"><el-input v-model="features_pe.dll" type="textarea" /></el-form-item>
            </el-form>
            <template #footer><el-button type="primary" @click="dialog_pe = false">关闭</el-button></template>
        </el-dialog>
        <el-dialog v-model="dialog_elf" title="特征预览">
            <el-form :model="features_elf" label-width="auto">
                <el-form-item label="static"><el-input v-model="features_elf.static" type="textarea" /></el-form-item>
            </el-form>
            <template #footer><el-button type="primary" @click="dialog_elf = false">关闭</el-button></template>
        </el-dialog>
    </div>
</template>

<script>
// @ is an alias to /src
import { reactive, ref } from "vue";
import Mycard from "@/components/Mycard.vue";
export default {
    components: {
        Mycard,
    },
    setup() {
        let pe_list = reactive([]);
        let pe_running = reactive([]);
        let feature_list = reactive([])
        let result_list = reactive([])
        return {
            activeName: ref("1"),
            current_card: "1",
            pe_switch: ref(true),
            pe_list,
            pe_running,
            feature_list,
            result_list,
            pe_interval: false,
            dialog_pe: ref(false),
            dialog_elf: ref(false),
            features_pe: reactive({
                api: '',
                dll: ''
            }),
            features_elf: reactive({
                static: ""
            })
        };
    },
    methods: {
        async format_check_pe(file) {
            if (file.type != "application/x-msdownload") {
                this.$message.error("上传文件格式必须为PE!")
                return false
            }
            let type = await this.file_type(file)
            if (type != "pe") {
                this.$message.error("上传文件格式必须为PE!")
                return false
            }
            return true
        },
        async format_check_elf(file) {
            let type = await this.file_type(file)
            if (type != "elf") {
                this.$message.error("上传文件格式必须为ELF!")
                return false
            }
            return true
        },
        file_type(file) {
            return new Promise((resovle, reject) => {
                console.log("filetype")
                const reader = new FileReader()
                reader.onload = (e) => {
                    const arrayBuffer = reader.result;
                    const magicNumber = this.getMagicNumber(arrayBuffer);
                    if (magicNumber) {
                        console.log('Magic Number:', magicNumber);

                        if (magicNumber === '504b0304') {
                            console.log('File format: APK');
                            resovle("apk")
                        } else if (magicNumber === '4d5a9000') {
                            console.log('File format: EXE');
                            resovle("pe")
                        } else if (magicNumber === '7f454c46') {
                            console.log('File format: ELF');
                            resovle('elf')
                        } else {
                            console.log('Unknown file format');
                            resovle("other")
                        }
                    }
                }
                reader.readAsArrayBuffer(file);
            })
        },
        format_check_json(file) {
            if (file.type != "application/json") {
                this.$message.error("上传文件格式必须为JSON!")
                return false
            }
            return true
        },
        getMagicNumber(arrayBuffer) {
            const uint8Array = new Uint8Array(arrayBuffer);
            let magicNumber = '';

            for (let i = 0; i < 4; i++) {
                const hex = uint8Array[i].toString(16).padStart(2, '0');
                magicNumber += hex;
            }

            return magicNumber;
        },
        download_features(type, filename, key) {
            console.log(type, filename)
            let url = "/download/" + type + "/" + key
            this.download(url, "features_" + filename)
        },
        view_features(type, filename, key, filetype) {
            let url = "/download/" + type + "/" + key
            this.$http.get(url).then(res => {
                console.log(res.data)
                if (filetype == "pe") {
                    this.dialog_pe = true
                    this.features_pe.api = res.data.api.join("\n")
                    this.features_pe.dll = res.data.dll.join("\n")
                } else {
                    this.dialog_elf = true
                    this.features_elf.static = res.data.static.join(', ')
                }
                // data = JSON.parse(res)
                // console.log(data)
            })
        },
        download(url, filename) {
            this.$http.get(url, { responseType: 'blob' }).then(res => {
                const fileURL = window.URL.createObjectURL(new Blob([res.data], { type: 'application/json' }))
                const link = document.createElement('a')
                link.href = fileURL
                link.download = filename.replace(/\.[^/.]+$/, "") + ".json"
                link.click()
            })
        },
        handleClick(tab, event) {
            console.log(tab.props.name);
            this.current_card = tab.props.name;
        },
        upload_vec(data) {
            console.log("upload vectors");
            const file = data.file;
            const key = this.generateRandomString();
            const formData = new FormData();
            formData.append("file", file);
            const fileinfo = {
                id: key,
                filename: file.name,
                filesize: file.size,
                filetype: file.type,
                state: "uploading",
                progress: 0,
                upload_time: new Date().getTime(),
            };
            this.result_list.unshift(fileinfo)
            console.log(key);
            this.$http
                .post("/pe/detect_vec", formData, {
                    onUploadProgress: (progressEvent) => {
                        const progress = Math.round(
                            (progressEvent.loaded / progressEvent.total) * 100
                        );
                        this.result_list.forEach((e) => {
                            if (e.id == key) {
                                e.progress = progress;
                            }
                        });
                    },
                })
                .then((res) => {
                    console.log(res); //处理
                    if (res.data.code == 200) {
                        this.result_list.forEach((e) => {
                            if (e.id == key) {
                                e.state = res.data.data.pred;
                            }
                        });
                    }
                    else {
                        this.result_list.forEach((e) => {
                            if (e.id == key) {
                                e.state = "error";
                            }
                        });
                    }
                });
        },
        upload(data) {
            console.log("upload");
            // console.log(data);
            const file = data.file;
            const key = this.generateRandomString();
            let flag = this.pe_switch ? "pe" : "elf"
            const formData = new FormData();
            formData.append("file", file);
            formData.append("key", key);
            formData.append("flag", flag);
            const fileinfo = {
                id: key,
                filename: file.name,
                filesize: file.size,
                filetype: flag,
                state: "uploading",
                progress: 0,
                upload_time: new Date().getTime(),
            };
            this.pe_list.unshift(fileinfo);
            console.log(key);
            this.$http
                .post("/file/analyse", formData, {
                    onUploadProgress: (progressEvent) => {
                        const progress = Math.round(
                            (progressEvent.loaded / progressEvent.total) * 100
                        );
                        this.pe_list.forEach((e) => {
                            if (e.id == key) {
                                e.progress = progress;
                            }
                        });
                    },
                })
                .then((res) => {
                    console.log(res); //处理
                    this.pe_list.forEach((e) => {
                        if (e.id == key) {
                            e.state = "analysing";
                        }
                    });
                    this.pe_running.push(key);
                    this.update();
                });
        },
        update() {
            if (this.pe_interval == false && this.pe_running.length != 0) {
                setTimeout(() => this.update_pe_state(), this.$config.update_interval);
                this.pe_interval = true;
            }
        },
        update_pe_state() {
            this.$http
                .post("/state/pe", { keylist: this.pe_running })
                .then((res) => {
                    console.log(res);
                    const state = new Map(Object.entries(res.data.data.state));
                    console.log(state);
                    for (let [key, val] of state) {
                        if (val != "analysing") {
                            let index = this.pe_running.indexOf(key);
                            if (index != -1) this.pe_running.splice(index, 1);
                            this.pe_list.forEach((e) => {
                                if (e.id == key) {
                                    e.state = val;
                                }
                            });
                        }
                    }
                    this.pe_interval = false;
                    this.update();
                });
        },
        generateRandomString() {
            let RANDOMKEY = 0;
            let str = "xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx".replace(
                /[xy]/g,
                function (c) {
                    var r = (Math.random() * 16) | 0,
                        v = c == "x" ? r : (r & 0x3) | 0x8;
                    return v.toString(16) + ++RANDOMKEY;
                }
            );
            return str.substring(str.length - 45);
        },
    },
};
</script>

<style lang="less" scoped>
.header {
    height: 60px;
    line-height: 60px;
    font-size: 40px;
    font-weight: bold;
    text-align: left;
    background-color: #fff;
    box-shadow: 0px 5px 5px -5px #888888;
}

.list_box {
    min-height: 300px;
}

.margin_right {
    margin-right: 25px;
}

.btn_group {
    text-align: left;
    display: flex
}
</style>
